package su.levenetc.ohos.entry;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.*;
import ohos.agp.components.Component.TouchEventListener;
import ohos.agp.utils.Point;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.multimodalinput.event.TouchEvent;
import su.levenetc.ohos.draggableview.DragController;
import su.levenetc.ohos.draggableview.DraggableView;
import su.levenetc.ohos.draggableview.RotateView;
import su.levenetc.ohos.draggableview.SkewView;
import su.levenetc.ohos.draggableview.utils.Utils;

/**
 * Created by Eugene Levenetc.
 */
public class SampleGridContainer extends StackLayout implements DragController.IDragViewGroup, Component.LayoutRefreshedListener, TouchEventListener {
    private DragController<SampleGridContainer> dragController = new DragController<>(this);
    private Component selectedView;
    private static final int MAX_COLUMNS = 3;
    private AnimatorValue dragStartAnimatorValue;
    private AnimatorValue dragEndAnimatorValue;

    public SampleGridContainer(Context context) {
        this(context, null);
    }

    public SampleGridContainer(Context context, AttrSet attrs) {
        super(context, attrs);
        setLayoutRefreshedListener(this);
        setTouchEventListener(this);
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        return dragController.onTouchEvent(touchEvent, component);
    }

    @Override
    public void onRefreshed(Component component) {
        final int width = getWidth();
        final int cellSize = width / MAX_COLUMNS;
        final int childCount = getChildCount();

        int x = 0;
        int y = 0;
        int col = 0;
        for (int i = 0; i < childCount; i++) {
            Component child = getComponentAt(i);
            child.setContentPositionX(x);
            child.setContentPositionY(y);
            child.setWidth(cellSize);
            child.setHeight(cellSize);
            col++;
            if (col == MAX_COLUMNS) {
                col = 0;
                y += cellSize;
            }

            x = col * cellSize;
        }
    }

    @Override
    public Component onDownEvent(int x, int y) {
        for (int i = 0; i < getChildCount(); i++) {
            Component child = getComponentAt(i);
            if (Utils.isViewContains(child, x, y, false)) {
                selectedView = child;
                return selectedView;
            }
        }
        return null;
    }

    @Override
    public ComponentContainer getContainerForDraggableView() {
        ComponentContainer rootView = getRootView(this);
        return (ComponentContainer) getComponentParent();
    }

    private ComponentContainer getRootView(ComponentContainer component) {
        if (component != null) {
            ComponentParent componentParent = component.getComponentParent();
            if (componentParent == null) {
                return component;
            } else {
                getRootView((ComponentContainer) componentParent);
            }
        }
        return null;
    }

    @Override
    public void onDragStart() {
        clearAnimation();
        dragStartAnimatorValue = new AnimatorValue();
        dragStartAnimatorValue.setDuration(500);
        float start = 1;
        float end = 0.5f;
        dragStartAnimatorValue.setValueUpdateListener((animatorValue1, v) -> {
            setAlpha(start + (end - start) * v);
        });
        dragStartAnimatorValue.start();
        selectedView.setVisibility(Component.INVISIBLE);
    }

    private void clearAnimation() {
        if (dragStartAnimatorValue != null) {
            dragStartAnimatorValue.stop();
        }
        if (dragEndAnimatorValue != null) {
            dragEndAnimatorValue.stop();
        }
    }

    @Override
    public void onDragEnd() {
        clearAnimation();//

        DraggableView draggableView = dragController.getDraggableView();

        float alphaStart = 0.5f;
        float alphaEnd = 1;
        float translationXStart = draggableView.getContentPositionX();
        float translationXEnd = selectedView.getContentPositionX() - draggableView.getXTranslation();
        float translationYStart = draggableView.getContentPositionY();
        float translationYEnd = selectedView.getContentPositionY() - draggableView.getYTranslation();
        dragEndAnimatorValue = new AnimatorValue();
        dragEndAnimatorValue.setDuration(300);
        dragEndAnimatorValue.setCurveType(Animator.CurveType.ACCELERATE_DECELERATE);
        dragEndAnimatorValue.setValueUpdateListener((animatorValue, v) -> {
            setAlpha(alphaStart + (alphaEnd - alphaStart) * v);
            draggableView.setTranslation(translationXStart + (translationXEnd - translationXStart) * v,
                    translationYStart + (translationYEnd - translationYStart) * v);
        });
        dragEndAnimatorValue.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
                dragController.finishDrag();
                selectedView.setVisibility(Component.VISIBLE);
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {
            }
        });
        dragEndAnimatorValue.start();
    }

    @Override
    public void onMoveEvent(float x, float y) {
    }

    @Override
    public DraggableView createDraggableView(
            PixelMap bitmap,
            VelocityDetector velocityTracker,
            Point selectedViewPoint,
            Point downEventPoint) {
        return new SkewView(
                getContext(),
                bitmap,
                velocityTracker,
                selectedViewPoint,
                downEventPoint,
                this
        );
    }
}